package com.easychat.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import com.easychat.config.AppConfig;
import com.easychat.entity.constants.Constants;
import com.easychat.entity.dto.MessageSendDTO;
import com.easychat.entity.dto.SysSettingDto;
import com.easychat.entity.dto.TokenUserInfoDto;
import com.easychat.entity.enums.*;
import com.easychat.entity.po.ChatSession;
import com.easychat.entity.po.UserContact;
import com.easychat.entity.query.ChatSessionQuery;
import com.easychat.entity.query.UserContactQuery;
import com.easychat.exception.BusinessException;
import com.easychat.mappers.ChatSessionMapper;
import com.easychat.mappers.UserContactMapper;
import com.easychat.utils.CopyTools;
import com.easychat.utils.DateUtil;
import com.easychat.utils.RedisUtil;
import com.easychat.websocket.MessageHandler;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.easychat.entity.query.ChatMessageQuery;
import com.easychat.entity.po.ChatMessage;
import com.easychat.entity.vo.PaginationResultVO;
import com.easychat.entity.query.SimplePage;
import com.easychat.mappers.ChatMessageMapper;
import com.easychat.service.ChatMessageService;
import com.easychat.utils.StringTools;
import org.springframework.web.multipart.MultipartFile;


/**
 * 消息记录表 业务接口实现
 */
@Service("chatMessageService")
public class ChatMessageServiceImpl implements ChatMessageService {

	private static final Logger log = LoggerFactory.getLogger(ChatMessageServiceImpl.class);
	@Resource
	private ChatMessageMapper<ChatMessage, ChatMessageQuery> chatMessageMapper;

	@Resource
	private ChatSessionMapper<ChatSession, ChatSessionQuery> chatSessionMapper;

	@Resource
	private MessageHandler messageHandler;

	@Resource
	private UserContactMapper<UserContact, UserContactQuery> userContactMapper;

	@Resource
	private AppConfig appConfig;

	@Resource
	private RedisUtil redisUtil;
    @Qualifier("redisTemplate")
    @Autowired
    private RedisTemplate redisTemplate;

	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<ChatMessage> findListByParam(ChatMessageQuery param) {
		return this.chatMessageMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(ChatMessageQuery param) {
		return this.chatMessageMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<ChatMessage> findListByPage(ChatMessageQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<ChatMessage> list = this.findListByParam(param);
		PaginationResultVO<ChatMessage> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(ChatMessage bean) {
		return this.chatMessageMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<ChatMessage> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.chatMessageMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<ChatMessage> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.chatMessageMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(ChatMessage bean, ChatMessageQuery param) {
		StringTools.checkParam(param);
		return this.chatMessageMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(ChatMessageQuery param) {
		StringTools.checkParam(param);
		return this.chatMessageMapper.deleteByParam(param);
	}

	/**
	 * 根据MessageId获取对象
	 */
	@Override
	public ChatMessage getChatMessageByMessageId(Long messageId) {
		return this.chatMessageMapper.selectByMessageId(messageId);
	}

	/**
	 * 根据MessageId修改
	 */
	@Override
	public Integer updateChatMessageByMessageId(ChatMessage bean, Long messageId) {
		return this.chatMessageMapper.updateByMessageId(bean, messageId);
	}

	/**
	 * 根据MessageId删除
	 */
	@Override
	public Integer deleteChatMessageByMessageId(Long messageId) {
		return this.chatMessageMapper.deleteByMessageId(messageId);
	}

	@Override
	public MessageSendDTO saveMessage(ChatMessage chatMessage, TokenUserInfoDto tokenUserInfoDto) {
		// 不是机器人回复，判断好友状态
		if (!Constants.BOOT_UID.equals(tokenUserInfoDto.getUserId())) {
			List<String> contactList = redisTemplate.opsForList().range(Constants.REDIS_KEY_USER_CONTACT + tokenUserInfoDto.getUserId(), 0, -1);
			if (!contactList.contains(chatMessage.getContactId())) {
				UserContactTypeEnum userContactTypeEnum = UserContactTypeEnum.getByPrefix(chatMessage.getContactId());
				if (UserContactTypeEnum.USER == userContactTypeEnum) {
					throw new BusinessException(ResponseCodeEnum.CODE_902);
				} else {
					throw new BusinessException(ResponseCodeEnum.CODE_903);
				}
			}
		}

		String sessionId = null;
		String sendUserId = tokenUserInfoDto.getUserId();
		String contactId = chatMessage.getContactId();
		Date curDate = new Date();
		UserContactTypeEnum userContactTypeEnum = UserContactTypeEnum.getByPrefix(contactId);

		if (userContactTypeEnum == UserContactTypeEnum.USER) {
			sessionId = StringTools.getChatSessionId4User(new String[] {sendUserId, contactId});
		} else {
			sessionId = StringTools.getChatSessionId4Group(contactId);
		}
		chatMessage.setSessionId(sessionId);
		chatMessage.setSendTime(curDate.getTime());
		MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByType(chatMessage.getMessageType());
		if (null == messageTypeEnum || !ArrayUtils.contains(new Integer[] {MessageTypeEnum.CHAT.getType(), MessageTypeEnum.MEDIA_CHAT.getType()}, chatMessage.getMessageType())) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}

		Integer status = MessageTypeEnum.MEDIA_CHAT.getType() == messageTypeEnum.getType() ? MessageStatusEnum.SENDED.getStatus() : MessageStatusEnum.SENDED.getStatus();
		chatMessage.setStatus(status);

		String messageContent = StringTools.clearnHtmlTag(chatMessage.getMessageContent());
		chatMessage.setMessageContent(messageContent);

		// 更新会话
		ChatSession chatSession = ChatSession.builder()
				.lastMessage(messageContent)
				.build();
		if (UserContactTypeEnum.GROUP == userContactTypeEnum) {
			chatSession.setLastMessage(tokenUserInfoDto.getNickName() + "：" + messageContent);
		}
		chatSession.setLastReceiveTime(curDate.getTime());
		this.chatSessionMapper.updateBySessionId(chatSession, sessionId);

		// 保存消息
		chatMessage.setSendUserId(sendUserId);
		chatMessage.setSendUserNickName(tokenUserInfoDto.getNickName());
		chatMessage.setContactType(userContactTypeEnum.getType());
		this.chatMessageMapper.insert(chatMessage);

		// 发消息
		MessageSendDTO messageSendDTO = CopyTools.copy(chatMessage, MessageSendDTO.class);

		if (Constants.BOOT_UID.equals(contactId)) {
			SysSettingDto sysSetting = redisUtil.getSysSetting();
			TokenUserInfoDto robotInfo = new TokenUserInfoDto();
			robotInfo.setUserId(sysSetting.getRobotUid());
			robotInfo.setNickName(sysSetting.getRobotNickName());
			ChatMessage robotMessage = ChatMessage.builder()
					.contactId(sessionId)
					.messageContent("机器人回复：你好，我是机器")
					.messageType(MessageTypeEnum.CHAT.getType())
					.build();
			saveMessage(robotMessage, robotInfo);
		} else {
			messageHandler.sendMessage(messageSendDTO);
		}
		return messageSendDTO;
	}

	@Override
	public void saveMessageFIle(String userId, Long messageId, MultipartFile file, MultipartFile cover) {
		ChatMessage chatMessage = this.chatMessageMapper.selectByMessageId(messageId);
		if (null == chatMessage) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		if (!chatMessage.getSendUserId().equals(userId)) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		SysSettingDto sysSetting = redisUtil.getSysSetting();

		String fileSuffix = StringTools.getFileSuffix(file.getOriginalFilename());
		if (!StringTools.isEmpty(fileSuffix)
				&& ArrayUtils.contains(Constants.IMAGE_SUFFIX_LIST, fileSuffix.toLowerCase())
				&& file.getSize() > sysSetting.getMaxImageSize() * Constants.FILE_SIZE) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		} else if (!StringTools.isEmpty(fileSuffix)
				&& ArrayUtils.contains(Constants.IMAGE_SUFFIX_LIST, fileSuffix.toLowerCase())
				&& file.getSize() > sysSetting.getMaxVideoSize() * Constants.FILE_SIZE) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		} else {
			if (file.getSize() > sysSetting.getMaxFileSize() * Constants.FILE_SIZE) {
				throw new BusinessException(ResponseCodeEnum.CODE_600);
			}
		}

		String filename = file.getOriginalFilename();
		String fileExtendName = StringTools.getFileSuffix(filename);
		String fileRealName = messageId + fileExtendName;
		String month = DateUtil.format(new Date(chatMessage.getSendTime()), DateTimePatternEnum.YYYYMM.getPattern());
		File folder = new File(appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + month);
		if (!folder.exists()) {
			folder.mkdirs();
		}
		File uploadFile = new File(folder.getPath() + "/" + fileRealName);
		try {
			file.transferTo(uploadFile);
			cover.transferTo(new File(uploadFile.getPath() + Constants.COVER_IMAGE_SUFFIX));
		} catch (IOException e) {
			log.error("上传文件失败", e);
			throw new BusinessException("上传文件失败");
		}

		ChatMessage uploadInfo = ChatMessage.builder()
				.status(MessageStatusEnum.SENDED.getStatus())
				.build();

		ChatMessageQuery chatMessageQuery = ChatMessageQuery.builder()
				.messageId(messageId)
				.status(MessageStatusEnum.SENDING.getStatus())
				.build();

		this.chatMessageMapper.updateByParam(uploadInfo, chatMessageQuery);

		MessageSendDTO messageSendDTO = new MessageSendDTO();
		messageSendDTO.setStatus(MessageStatusEnum.SENDED.getStatus());
		messageSendDTO.setMessageId(messageId);
		messageSendDTO.setMessageType(MessageTypeEnum.FILE_UPLOAD.getType());
		messageSendDTO.setContactId(chatMessage.getContactId());
		messageHandler.sendMessage(messageSendDTO);
	}

	@Override
	public File downlodFile(TokenUserInfoDto tokenUserInfoDto, Long fileId, Boolean showCover) {
		ChatMessage chatMessage = this.chatMessageMapper.selectByMessageId(fileId);
		String contactId = chatMessage.getContactId();
		UserContactTypeEnum userContactTypeEnum = UserContactTypeEnum.getByPrefix(contactId);
		if (userContactTypeEnum == UserContactTypeEnum.USER && !tokenUserInfoDto.getUserId().equals(chatMessage.getContactId())) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		if (userContactTypeEnum == UserContactTypeEnum.GROUP) {
			UserContactQuery userContactQuery = new UserContactQuery();
			userContactQuery.setUserId(tokenUserInfoDto.getUserId());
			userContactQuery.setContactType(UserContactTypeEnum.GROUP.getType());
			userContactQuery.setContactId(contactId);
			userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
			Integer count = this.userContactMapper.selectCount(userContactQuery);
			if (count == 0) {
				throw new BusinessException(ResponseCodeEnum.CODE_600);
			}
		}

		String month = DateUtil.format(new Date(chatMessage.getSendTime()), DateTimePatternEnum.YYYYMM.getPattern());
		File folder = new File(appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + month);
		if (!folder.exists()) {
			folder.mkdirs();
		}

		String fileName = chatMessage.getFileName();
		String fileExtendName = StringTools.getFileSuffix(fileName);
		String fileRealName = fileId + fileExtendName;

		if (showCover != null && showCover) {
			fileRealName = fileRealName + Constants.COVER_IMAGE_SUFFIX;
		}
		File file = new File(folder.getPath() + "/" + fileRealName);
		if (!file.exists()) {
			log.info("文件不存在 {}", fileId);
			throw new BusinessException(ResponseCodeEnum.CODE_602);
		}
		return file;
	}
}